package com.golf.comms.server;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.LinkedBlockingQueue;

import javax.management.MBeanServer;

import org.apache.log4j.Logger;
import org.jboss.remoting.InvocationRequest;
import org.jboss.remoting.ServerInvocationHandler;
import org.jboss.remoting.ServerInvoker;
import org.jboss.remoting.callback.Callback;
import org.jboss.remoting.callback.HandleCallbackException;
import org.jboss.remoting.callback.InvokerCallbackHandler;

import com.golf.comms.protocol.ChatMessage;

/**
 * 
 * 
 * @author gfloodgate
 */
public class LobbyChatInvocationHandler implements ServerInvocationHandler, Runnable
{
	
	/** The logger instance. */
	private static final Logger log = Logger.getLogger(LobbyChatInvocationHandler.class);
	
	
	/** The list of registered callback handlers. */
	private List<InvokerCallbackHandler> callbackHandlers = new CopyOnWriteArrayList<InvokerCallbackHandler>();
	
	/** The queue of waiting message for other chat parties. */
	private LinkedBlockingQueue<ChatMessage> messages = new LinkedBlockingQueue<ChatMessage>();
	
	/** The flag indicating if any listeners are registered for callbacks. */
	private volatile boolean isListening;
	
	
	/**
	 * Create the handler, and start it's manager thread.
	 * TODO: MESSY, allow thread start and shutdown cleanly.
	 */
	public LobbyChatInvocationHandler()
	{
		final Thread manager = new Thread(this);
		manager.setDaemon(true);
		manager.start();
	}
	
	
	/**
	 * {@inheritDoc}
	 */
	public void addListener(final InvokerCallbackHandler handler)
	{
		callbackHandlers.add(handler);
		isListening = true;
		
		if (log.isDebugEnabled())
		{
			log.debug("Client callback listener registered.");
		}
	}

	
	/**
	 * {@inheritDoc}
	 */
	public void removeListener(final InvokerCallbackHandler handler)
	{
		callbackHandlers.remove(handler);
		if (callbackHandlers.size() == 0)
		{
			isListening = false;
		}

		if (log.isDebugEnabled())
		{
			log.debug("Client callback listener unregistered.");
		}
	}

	
	/**
	 * {@inheritDoc}
	 */
	public Object invoke(final InvocationRequest request) throws Throwable
	{
		final ChatMessage message = (ChatMessage)request.getParameter();
		message.setTime(new Date());
		
		messages.put(message);
		
		return null;
	}
	
	
	/**
	 * {@inheritDoc}
	 */
	public void setInvoker(final ServerInvoker invoker)
	{
		// Do nothing.
	}

	
	/**
	 * {@inheritDoc}
	 */
	public void setMBeanServer(final MBeanServer server)
	{
		// Do nothing.
	}

	
	/** 
	 * {@inheritDoc}
	 */
	public void run()
	{
		while (true)
		{
			while (isListening)
			{
			    try
			    {
		    		final ChatMessage message = messages.take();
					Callback callback = new Callback(message);
   
					for (final InvokerCallbackHandler handler : callbackHandlers)
					{
						try
						{
							handler.handleCallback(callback);
						}
						catch(HandleCallbackException e)
						{
							e.printStackTrace();
						}			
					}
			    }
			    catch (InterruptedException ie)
			    {
			    	// Can't do anything.
			    }
	               
				sleep(500);
			}
			
			sleep(1000);
		}
	}
	
	
	/**
	 * 
	 * 
	 * @param milli
	 */
	private void sleep(final long milli)
	{
		try
		{
			Thread.sleep(milli);
		}
		catch (InterruptedException ie)
		{
			// Do nothing.
		}
	}
	
}
